﻿namespace Business.Repositories
open System;
open System.Data;
open System.Collections.Generic;
open System.ComponentModel.DataAnnotations;
open System.ComponentModel.DataAnnotations.Schema;
open System.Data.Entity;
open System.Data.Linq
open System.Linq


#region
//module Repository
//module Data =
// type DataContext(connectionString:string) as t =
//   inherit DbContext(connectionString)
//   //[<DefaultValue>] val UserProfile:
// 
// type Tag() =
//    [<DefaultValue>] val mutable Tag:string
//    [<DefaultValue>] val mutable position:int
// 
// type Url() =
//    [<DefaultValue>] val mutable Uri: string
//    [<DefaultValue>] val mutable HostUrl:string
//    [<DefaultValue>] val mutable Title : string
//    [<DefaultValue>] val mutable Description:string
//    [<DefaultValue>] val mutable Content:string
//    [<DefaultValue>] val mutable PrintScreenUrl:string
//    [<DefaultValue>] val mutable Favicon:string
//    [<DefaultValue>] val mutable position:int
//    [<DefaultValue>] val mutable isFile:bool
// type Bookmark() =
//    [<DefaultValue>] val mutable Id:Guid
//    [<DefaultValue>] val mutable Tag:string
//    [<DefaultValue>] val mutable Uri:string
//    [<DefaultValue>] val mutable IsPublic:bool
//    [<DefaultValue>] val mutable position:int
//
//    [<DefaultValue>] val mutable _tag:Tag
//    abstract tag: Tag with get,set
//    default t.tag with get() = t._tag and set(v) = t._tag <- v
//
//    [<DefaultValue>] val mutable _uri:Uri
//    abstract uri: Uri with get,set
//    default t.uri with get() = t._uri and set(v) = t._uri <- v
// 
// type UserBookmark() =
//    [<DefaultValue>] val mutable Id:Guid
//    [<DefaultValue>] val mutable BookmarkId:Guid
//    [<DefaultValue>] val mutable UserId: int
//    [<DefaultValue>] val mutable position:int
//
//    [<DefaultValue>] val mutable _bookmark:Bookmark
//    abstract bookmark: Bookmark with get,set
//    default t.bookmark with get() = t._bookmark and set(v) = t._bookmark <- v
//
// type UserUrlSettings() =
//    [<DefaultValue>] val mutable UserId:int
//    [<DefaultValue>] val mutable Uri:string
//    [<DefaultValue>] val mutable Title:string
// 
//  type UserProfile() = 
//      [<DefaultValue>] val mutable Id:int
//      [<DefaultValue>] val mutable UserName:string
//      [<DefaultValue>] val mutable Email:string
//
//      [<DefaultValue>] val mutable _bookmarks: ICollection<UserBookmark>
//      abstract bookmarks: ICollection<UserBookmark> with get,set
//      default t.bookmarks with get() = t._bookmarks and set(v) = t._bookmarks <- v
#endregion
[<AutoOpen>]
module Repository =
 type IRepository<'T when 'T : not struct> =
    abstract GetAll:unit -> IQueryable<'T>
    abstract Filter:  Quotations.Expr<('T -> bool)> -> IQueryable<'T>
    abstract FilterOne : Quotations.Expr<('T -> bool)> -> 'T
    abstract Update : 'T -> 'T
    abstract Create : 'T -> 'T
    abstract Delete : 'T -> 'T
    abstract Detach : 'T -> 'T
    abstract Unchanged : 'T -> 'T
    //abstract Query : (IQueryable<'T> -> IQueryable<'b>) -> IQueryable<'b>


 type Repository<'T when 'T : not struct>(data:Data.DataContext) = //connectionString:string) =
   //let data:Data.DataContext = new Data.DataContext(connectionString)
   member private r.set = data.Set<'T>()
   interface IRepository<'T> with
     member r.GetAll() = r.set :> IQueryable<'T>
     member r.Filter filter =  <@ query.Select( query.Where(query.Source(r.set), %filter),fun x -> x) @> |> query.Run
//                                     
//        query { for x in r.set do 
//                   where (filter x)
//                   select x }
     member r.FilterOne filter  = <@ query.HeadOrDefault( query.Select( query.Where(query.Source(r.set), %filter),fun x -> x)) @> |> query.Run
//        query { for x in r.set do 
//                 where (filter x)
//                 headOrDefault
//                 }
     member r.Update s =
        data.Entry(s:'T).State <- EntityState.Modified
        s
     member r.Delete s =
         data.Entry(s:'T).State <- EntityState.Deleted 
         s
     member r.Create s =
         data.Entry(s:'T).State <- EntityState.Added 
         s
     member r.Detach s = 
         data.Entry(s:'T).State <- EntityState.Detached
         s
     member r.Unchanged s = 
         data.Entry(s:'T).State <- EntityState.Unchanged
         s
   member r.GetAll = (r:>IRepository<'T>).GetAll
   member r.Filter filter = (r :> IRepository<'T>).Filter filter
   member r.FilterOne filter = (r :> IRepository<'T>).FilterOne filter
   member r.Update s = (r :> IRepository<'T>).Update s
   member r.Delete s = (r :> IRepository<'T>).Delete s
   member r.Create s = (r :> IRepository<'T>).Create s
   member r.Detach s = (r :> IRepository<'T>).Detach s
   member r.Unchanged s = (r :> IRepository<'T>).Unchanged s
   //member r.Query source = 
          // query { for t in (source (r.GetAll()) ) do
                   // select t }
//   member r.tmp = Microsoft.FSharp.Linq.QueryBuilder().wh
[<AutoOpen>]
module UnitOfWork =
  type IUow =
    abstract member Users : IRepository<Data.UserProfile>
    abstract member Reports : IRepository<Data.UserReport>
    abstract member UsersBookmarks : IRepository<Data.UserBookmark>
    abstract member Tags : IRepository<Data.Tag>
    abstract member Url : IRepository<Data.Url>
    abstract member Bookmarks : IRepository<Data.Bookmark>
    abstract  member UrlSettings : IRepository<Data.UserUrlSettings>
    abstract member Commit:unit -> int
  
  type Uow(data:Data.DataContext, users: IRepository<Data.UserProfile>, reports : IRepository<Data.UserReport>, usersBookmarks : IRepository<Data.UserBookmark>, tags : IRepository<Data.Tag>, url : IRepository<Data.Url>, bookmarks : IRepository<Data.Bookmark>, urlSettings : IRepository<Data.UserUrlSettings>) =
    interface IUow with 
      member x.Users = users
      member x.Reports = reports
      member x.UsersBookmarks = usersBookmarks
      member x.Tags = tags
      member x.Url = url
      member x.Bookmarks = bookmarks
      member x.UrlSettings = urlSettings
      override x.Commit() = data.SaveChanges()